package com.pro.framework.javatodb.service;

import com.pro.framework.javatodb.constant.JTDConst;
import com.pro.framework.javatodb.constant.JTDConstInner;
import com.pro.framework.javatodb.model.JTDSequenceInfo;
import com.pro.framework.javatodb.model.JTDSqlInfo;
import com.pro.framework.javatodb.model.JTDTableInfo;
import com.pro.framework.javatodb.util.JTDUtil;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class JTDTableMetaServiceSequenceImpl implements JTDTableMetaService {
    public static final JTDTableMetaService INSTANCE = new JTDTableMetaServiceSequenceImpl();

    @Override
    public Serializable getVersionSequence(JTDTableInfo table) {
        if (table.getTableName().equals("launch_prohibited_word")) {
            int i = 0;
        }
        return null == table.getSequences() ? null : table.getSequences().stream().mapToInt(JTDSequenceInfo::hashCode).sum();
    }

    @Override
    public List<JTDSqlInfo> calculateAlterTableSqls(JTDTableInfo told, JTDTableInfo tnew) {
        Map<String, JTDSequenceInfo> sequenceInfoMap = JTDUtil.listToMap(told.getSequences(), JTDSequenceInfo::getName);
        String tableName = tnew.getTableName();
        List<JTDSqlInfo> addOrModify = tnew.getSequences().stream().map(newSeq -> {
            String sequenceName = newSeq.getName();
//                        String info = newSeq.getValue();
            boolean isOldExist = sequenceInfoMap.containsKey(sequenceName);
            if (isOldExist && newSeq.equals(sequenceInfoMap.get(sequenceName))) {
                return null;
            }

            String dropSql = MessageFormat.format("DROP INDEX `{0}` ON `{1}`;\n", sequenceName, tableName);
            String sql = newSeq.toSql(tableName);
            String sqlPrepared = "";
            // 唯一索引 空字符串 默认改成NUll
            if (JTDConstInner.EnumSequenceType.UNIQUE_KEY.equals(newSeq.getType()) && newSeq.getFields().size() == 1) {
                String fieldName = newSeq.getFields().get(0).getExpression();
                sqlPrepared = MessageFormat.format("update `{0}` set {1} = NULL where {2} = '''';", tableName, fieldName, fieldName);
            }
            String addSql;
            if (JTDConstInner.EnumSequenceType.EXPRESSION_UNIQUE_INDEX.equals(newSeq.getType())) {
                // 已是完整 CREATE 语句，不再加 ALTER TABLE
                String head = sql.substring(0, sql.indexOf("("));
                String fields = sql.substring(sql.indexOf("("));
                addSql = MessageFormat.format("CREATE {0} ON `{1}` {2}", head, tableName, fields);
            } else {
                addSql = MessageFormat.format("ALTER TABLE `{0}` ADD {1};", tableName, sql);
            }
            String content = (isOldExist ? dropSql : "") + sqlPrepared + addSql;
            JTDConst.EnumSqlRunType runType = isOldExist ? JTDConst.EnumSqlRunType.createModifyTableAndMetas : JTDConst.EnumSqlRunType.createTableAndMetas;
            return new JTDSqlInfo(runType, content, tnew.getSize());
        }).filter(Objects::nonNull).collect(Collectors.toList());

        List<String> newNames = tnew.getSequences().stream().map(JTDSequenceInfo::getName).collect(Collectors.toList());
        List<JTDSqlInfo> delete = told.getSequences().stream()
                .map(JTDSequenceInfo::getName)
                .filter(oldName -> !newNames.contains(oldName))
                .distinct().map(oldName -> {
                    String sqlHeader = "ALTER TABLE `{0}` DROP INDEX `{1}`";
                    String content = MessageFormat.format(sqlHeader, tableName, oldName);
                    JTDConst.EnumSqlRunType runType = JTDConst.EnumSqlRunType.createModifyDeleteAll;
                    return new JTDSqlInfo(runType, content, tnew.getSize());
                }).collect(Collectors.toList());
        List<JTDSqlInfo> list = new ArrayList<>();
        list.addAll(addOrModify);
        list.addAll(delete);
        return list;
    }
}
